/**
 * 背景：
 *    现在整个rn项目打包后，jsbundle体积有3.2M，后续版本迭代后，体积将更大。
 *
 * 功能：
 *    将jsbundle文件分割为2个文件，第一个文件是入口相关的代码，例如基础库、首页等，
 *    第2个文件是其它页面，如活动页、结算页、收银台、订单详情，等不需要已进入时就加载的代码。
 */
const file = require('../common/file');
const path = require('path');
let acorn = require('../common/acorn.js');
const match_pages_file = require('./match_pages_file');
const is__d_call = require('./is__d_call');
const get_define_number = require('./get_define_number');
const parse_pages_from_pages_file = require('./parse_pages_from_pages_file');
const get_dependencies_list_in___d_call = require('./get_dependencies_list_in___d_call');
const spawnSync = require('child_process').spawnSync;
const color = require('../common/colors-cli/lib/index.js');
const utility = require('../common/utility.js');
const replace_bundle_folder_for_print = utility.replace_bundle_folder_for_print;
const write_comment_file = utility.write_comment_file;
const count__d_call_percentage = require('./count__d_call_percentage.js');
const remove_jdreact_core_lib = require('./remove_jdreact_core_lib.js');

// 重要： todo ： 收集所有与预期不一致的结构，并输出，打包压缩时需检查所有内容，或如果存在不一致预期，直接终止拆包


function find_pages_file(ast,jsbundle_code){
	var pages_code , pages_ast;
	var body = ast.body;
	for(var i=0; i<body.length; i++){
		var itm_ast = body[i];
		var type = itm_ast.type;
		var start = itm_ast.start;
		var end = itm_ast.end;
		var code = jsbundle_code.substring(start,end);
		var is_pages_file = match_pages_file(code,itm_ast);
		//is_pages_file && file.writeFileSync('./example_code/pages.js',code);
		if(is_pages_file){
			// 进入这个if，说明找到了两个地方都符合pages.js的内容
			if(pages_ast||pages_code){
				console.log('出错了');
				//break;
				return null;
			}
			pages_ast = itm_ast;
			pages_code = code;
		}
	}
	if(pages_ast&&pages_code){
		return {
			pages_code:pages_code,
			pages_ast:pages_ast
		}
	} else {
		return null;
	}
}

// 解析所有的定义与依赖
function parse_all_define_and_dependency(ast,jsbundle_code) {
	var hash_obj = {};
	var body = ast.body;
	var error_list = [];
	for(var i=0; i<body.length; i++){
		var itm_ast = body[i];
		//var type = itm_ast.type;
		if(is__d_call(itm_ast)){
			var define_number = get_define_number(itm_ast);
			var dependencies_list = get_dependencies_list_in___d_call(itm_ast);
			if(typeof dependencies_list==='string'){
				console.log('错误：'+dependencies_list);
			}
			if(dependencies_list&&(!dependencies_list.length)){
				//error_list.push(jsbundle_code.substring(itm_ast.start,itm_ast.end));
			}
			if((typeof define_number==='number') && (dependencies_list&&dependencies_list.push)){
				hash_obj[define_number] = dependencies_list;
			}
		}
	}
	//file.writeFileSync('./example_code/define_and_dependency_error_list.json',error_list.join('\n\n\n\n'));
	return hash_obj;
}

function do_split(jsbundle_folder) {
	var all_files = file.getAllFilepathInDirSync(jsbundle_folder,function (fullpath,stat,filename) {
		if(filename.match(/\.jsbundle$/)){
			return true;
		}
	},true);

	if((!all_files)||(!all_files[0])){
		var error_msg = '没有找到.jsbundle文件';
		console.log(color.red(error_msg));
		return error_msg;
	}
	if(all_files.length>1){
		var error_msg = '找到多个.jsbundle文件';
		console.log(color.red(error_msg));
		return error_msg;
	}
	// 读取文件内容
	var js_code_filepath = all_files[0];
	var jsbundle_code = file.readFileSync(js_code_filepath);

	var ast = acorn.parse(jsbundle_code,{ranges:true});
	var body = ast.body;


// __d(...)的个数比例必须大于80%
	var percentage = count__d_call_percentage(ast);
	if (percentage < 0.80) {
		var error_msg = '文件内容可能和预期的不一致';
		console.log(error_msg);
		return error_msg;
	} else {
		//console.log('__d()比例=' + percentage);
	}

	var pages_obj = find_pages_file(ast, jsbundle_code);
	if(!pages_obj){
		return '未找到pages.js所对应的内容';
	}

	//var {pages_code,pages_ast} = pages_obj;
	var pages_code = pages_obj.pages_code;
	var pages_ast = pages_obj.pages_ast;

	//file.writeFileSync('./example_code/pages.json',JSON.stringify(pages_ast,null,4));
	// 解析出pages.js中的所有页面
	var requires_obj = parse_pages_from_pages_file(jsbundle_code, pages_code, pages_ast);
	if(!requires_obj){
		return 'pages.js内容解析失败';
	}
	//write_comment_file('requires_obj.json',requires_obj);

	var first_file_pages = requires_obj.first_file_pages;// Int数组
	var other_file_pages = requires_obj.other_file_pages;// Int数组
	if(first_file_pages.length===0){
		return '请查看pages.js中是否有定义first_file_in_jsbundles=true的页面';
	}
	if(other_file_pages.length===0){
		return '没有找到要拆分出的页面，请检查问题';
	}

	//console.log(JSON.stringify(requires_obj));


	// 返回值是Int类型
	var pages_file_define_number = get_define_number(pages_ast);
	// console.log('pages_file_define_number = '+pages_file_define_number);

	// define_and_dependency[k] = value 意义：编号为k的模块，用到了value中的所有编号模块
	var define_and_dependency = parse_all_define_and_dependency(ast,jsbundle_code);
	//write_comment_file('define_and_dependency.json',define_and_dependency);


	// 反转define_and_dependency，求出每一个模块都被哪些模块使用了
	// 使用方式：当需要知道某个模块A是否被另一个模块USER使用时，判断module_used_by[A][USER]是否为true即可
	var module_used_by = {};
	var all_modules = [];
	for(var k in define_and_dependency){
		var k_int = parseInt(k,10);
		all_modules.push(k_int);
		var dependency_list = define_and_dependency[k];
		for(var i=0; i<dependency_list.length; i++){
			var module_number = dependency_list[i];
			module_used_by[module_number] || (module_used_by[module_number]=[]);
			(module_used_by[module_number].indexOf(k_int)===-1) && module_used_by[module_number].push(k_int);
		}
	}
	//write_comment_file('module_used_by.json',module_used_by);

	// 只被pages.js用到吗？
	function use_only_by_pages(all_user_array) {
		var use_only_by_pages_define_file = all_user_array&&all_user_array.length===1&&all_user_array[0]===pages_file_define_number;
		return !!use_only_by_pages_define_file;
	}

	// 获取被使用线路图， 并搜集最后被谁使用，并以pages.js为终点。
	// pages_file_define_number
	console.log('pages_file_define_number = ' + pages_file_define_number + ' , type=' + (typeof pages_file_define_number));
	function get_the_end_user(module_id) {
		if(module_id==pages_file_define_number){// 用==，不用===，因为不确定是'12'还是12
			return [];
		}
		var usedBy = module_used_by[module_id];
		if((!usedBy)||(!usedBy.length)){
			return null;
		}

		usedBy = [].concat(usedBy);// clone
		if(use_only_by_pages(usedBy)){
			return [module_id];
		}

		var len = usedBy.length;
		var the_ends = [];
		//console.log('usedBy = '+JSON.stringify(usedBy));
		for(var i=0; i<len; i++){
			var id = usedBy[i];

			if((id==pages_file_define_number)){// 用==，不用===，因为不确定是'12'还是12
				the_ends.push(module_id);
			} else {
				var has_more_user = get_the_end_user(id);
				if(has_more_user===null){
					the_ends.push(id);
				} else {
					the_ends = the_ends.concat(has_more_user);
				}
			}
		}
		return the_ends;
	}

	// var r = get_the_end_user(821);
	// console.log('end users = '+r);
	//
	// return 'eee';

	// list是Int数组
	function all_keys_in_the_list(keys,list) {
		var is_in = true;

	}
	// 子数组
	function is_sub_array(sub_array,full_array) {
		if(!sub_array){
			return true;
		}
		//var is_sub = true;
		for(var i=0; i<sub_array.length; i++){
			if(full_array.indexOf(sub_array[i])===-1){
				//is_sub = false;
				return false;
			}
		}
		return true;
	}

	// 仅出现在other_file_pages
	function only_in_other_file_pages(module_id) {
		var end_uses_arr = get_the_end_user(module_id);
		return is_sub_array(end_uses_arr,other_file_pages);
	}

	// unuse_list表示入口文件不需要，可以放置到第2个文件
	var unuse_list = [].concat(other_file_pages);// Int数组
	var exclude_list = [];
	console.log('init unuse_list长度='+unuse_list.length);
	// 找出unuse_list中，不仅仅是被pages.js引用的模块
	for(var i=0; i<unuse_list.length; i++){
		var unuse_list_item_id = unuse_list[i];
		const all_user_array = module_used_by[unuse_list_item_id];
		// 只被pages.js用到吗？
		var use_only_by_pages_define_file = all_user_array&&all_user_array.length===1&&all_user_array[0]===pages_file_define_number;
		if(use_only_by_pages_define_file){

		} else {
			var double__but__only_in_other_file_pages = only_in_other_file_pages(unuse_list_item_id);
			if(double__but__only_in_other_file_pages){

			} else {
				exclude_list.push(unuse_list_item_id);
				unuse_list.splice(i--,1);
			}
		}
	}
	console.log('踢出pages.js之外引用后， unuse_list长度='+unuse_list.length);
	console.log('exclude_list='+exclude_list.join(','));
	// 1159,1245,1229,1748,1746,2012,1114


	var still_has_unuse = true;
	var max_loop = 99; // 一般9次以内足以，如果99次了，说明有问题。那么，什么时候会导致出现这么多次的遍历了？
	var loop_count = 0;
	var too_many_loop = false;
	var start_time = (new Date()).getTime();
	while(still_has_unuse){

		if(loop_count>max_loop){
			too_many_loop = true;
			break;
		}
		var find_change = false;
		for(var i=0; i<all_modules.length; i++){
			var target = all_modules[i];
			if(unuse_list.indexOf(target)!==-1){
				//all_modules.splice(i--,1);//删除，但不用push到unuse_list，因为已经存在
				continue;
			}
			var all_user_array = module_used_by[target];
			// 说明这个模块不被任何__d()中的模块使用，例如AppRegistry.registerComponent('JDReactDaoJia',XXX)这个模块
			if(!all_user_array || !all_user_array.length){
				//console.log('all_user_array : '+all_user_array + ' , target='+target);
				all_modules.splice(i--,1);//删除，但不用push到unuse_list，因为需要在第一个文件中用到
				continue;
			}
			var just_used_by_subpages = all_user_array&&all_user_array.length&&is_sub_array(all_user_array,unuse_list);
			if(just_used_by_subpages){
				unuse_list.push(target);
				all_modules.splice(i--,1);
				find_change = true;
			} // else {
			// 	// 进入else说明这个文件被第1个文件需要。
			// 	// 如果发现一个模块被第1个文件需要，同时还出现在unuse_list数组中，那么应该从unuse_list中剔除
			// 	var indexOf_in_unuse_list = unuse_list.indexOf(target);
			// 	if(indexOf_in_unuse_list!==-1){
			// 		unuse_list.splice(indexOf_in_unuse_list,1);
			// 		find_change = true;
			// 	}
			// }
		}
		(!find_change) && (still_has_unuse=false);

		loop_count++;
	}
	var end_time = (new Date()).getTime();
	console.log('遍历耗时='+(end_time-start_time));

	console.log('共拆分出'+unuse_list.length+'个模块');
	console.log('loop_count = '+loop_count);

	// 拆分实际代码
// ifIsEntrance   first_file_in_jsbundles   CartlistForpage

	var first_file_code = '';
	var second_file_code = '';
	for(var i=0; i<body.length; i++){
		const itm_ast = body[i];
		var start = itm_ast.start;
		var end = itm_ast.end;
		if(body[i+1]){
			var start_of_next_itm = body[i+1].start;
			end = start_of_next_itm;
		}
		var code = jsbundle_code.substring(start,end);//[start,end) 包含start，不包含end

		if(is__d_call(itm_ast)){
			var define_number = get_define_number(itm_ast);
			var is_second_file_code = unuse_list.indexOf(define_number)!==-1;
			if(is_second_file_code){

				second_file_code += code;

			} else {
				first_file_code += code;
			}
		} else {
			first_file_code += code;
		}
	}

	//todo first_file_code += '\n//# sourceMappingURL=JDReactDaoJia.map';

	console.log('jsbundle_code总长度='+jsbundle_code.length);
	console.log('第1个文件长度='+first_file_code.length);
	console.log('第2个文件长度='+second_file_code.length);
	console.log('拆分后2个文件体积和 = ' + (first_file_code.length+second_file_code.length));


	console.log('js_code_filepath = '+replace_bundle_folder_for_print(js_code_filepath));
	console.log('second_file_code = '+replace_bundle_folder_for_print(path.join(jsbundle_folder,'second_file_code.js')));

	file.writeFileSync(js_code_filepath,first_file_code);
	file.writeFileSync(path.join(jsbundle_folder,'second_file_code.js'),second_file_code);


	return true;
	//return remove_jdreact_core_lib(jsbundle_folder);
}

//do_split();


module.exports = do_split;